#ifndef __QE_DEVICE_H__
#define __QE_DEVICE_H__



#include "qe_def.h"
#include "qe_list.h"



/**
 * device (I/O) class type
 */
typedef enum {
	QE_DEV_NONE = -1,
	QE_DEV_CHAR = 0,	/* character device */
	QE_DEV_BLOCK,
	QE_DEV_NETIF,
	QE_DEV_MTD,
	QE_DEV_CAN,
	QE_DEV_RTC,
	QE_DEV_SOUND,
	QE_DEV_GRAPHIC,
	QE_DEV_I2CBUS,
	QE_DEV_USB_DEVICE,
	QE_DEV_USB_HOST,
	QE_DEV_SPI_BUS,
	QE_DEV_SPI_DEVICE,
	QE_DEV_SDIO,
	QE_DEV_PM,
	QE_DEV_PIPE,
	QE_DEV_PORTAL,
	QE_DEV_TIMER,
	QE_DEV_GPIO,
	QE_DEV_INTC,
	QE_DEV_MISCELLANEOUS,
	QE_DEV_SENSOR,
	QE_DEV_IMGSENSOR,
	QE_DEV_TOUCH,
	QE_DEV_PHY,
	QE_DEV_SIZEOF,
}qe_dev_type;



/**
 * device flags defitions
 */
#define QE_DEV_F_DEACTIVATE       	0x000           /**< device is not not initialized */

#define QE_DEV_F_RDONLY           	0x001           /**< read only */
#define QE_DEV_F_WRONLY           	0x002           /**< write only */
#define QE_DEV_F_RDWR             	0x003           /**< read and write */

#define QE_DEV_F_REMOVABLE        	0x004           /**< removable device */
#define QE_DEV_F_STANDALONE       	0x008           /**< standalone device */
#define QE_DEV_F_ACTIVATED        	0x010           /**< device is activated */
#define QE_DEV_F_SUSPENDED        	0x020           /**< device is suspended */
#define QE_DEV_F_STREAM           	0x040           /**< stream mode */

#define QE_DEV_F_INT_RX           	0x100           /**< INT mode on Rx */
#define QE_DEV_F_DMA_RX           	0x200           /**< DMA mode on Rx */
#define QE_DEV_F_INT_TX           	0x400           /**< INT mode on Tx */
#define QE_DEV_F_DMA_TX           	0x800           /**< DMA mode on Tx */

#define QE_DEV_OF_CLOSE           	0x000           /**< device is closed */
#define QE_DEV_OF_OPEN            	0x008           /**< device is opened */
#define QE_DEV_OF_MASK            	0xf0f           /**< mask of open flag */

#define QE_DEV_IOC_RESUME     		0x01            /**< resume device */
#define QE_DEV_IOC_SUSPEND     		0x02            /**< suspend device */
#define QE_DEV_IOC_CONFIG     		0x03            /**< configure device */
#define QE_DEV_IOC_CLOSE     		0x04            /**< close device */
#define QE_DEV_IOC_GET_NAME	  		0x05
#define QE_DEV_IOC_SET_NAME	  		0X06

#define QE_DEV_IOC_SET_INT      	0x10            /**< set interrupt */
#define QE_DEV_IOC_CLR_INT      	0x11            /**< clear interrupt */
#define QE_DEV_CTRL_GET_INT       	0x12            /**< get interrupt status */
#define QE_DEV_IOC_CUSTOM_START		0x20
#define QE_DEV_IOC(n)				(QE_DEV_IOC_CUSTOM_START + n)


typedef qe_ret (*qe_bus_lock_func)(qe_ptr ref, qe_int timeout_ms);
typedef void (*qe_bus_unlock_func)(qe_ptr ref);

struct qe_device;
typedef struct qe_device qe_dev;

typedef qe_ret (*qe_dev_rx_indicate_func)(qe_dev *, qe_size);
typedef qe_ret (*qe_dev_tx_complete_func)(qe_dev *, qe_ptr);

typedef struct
{
	qe_const_str compatible;
	qe_ubase data;
} qe_device_id;

/**
 * operations set for device object
 */
typedef struct {
    /* common device interface */
    qe_ret   (*init)  (qe_dev *dev);
    qe_ret   (*open)  (qe_dev *dev, qe_u16 oflag);
    qe_ret   (*close) (qe_dev *dev);
    qe_size  (*read)  (qe_dev *dev, qe_offs pos, qe_ptr buffer, qe_size size);
    qe_size  (*write) (qe_dev *dev, qe_offs pos, qe_const_ptr buffer, qe_size size);
    qe_ret   (*ioctl) (qe_dev *dev, qe_int cmd, qe_ptr args);
}qe_dev_ops;

/**
 * Device structure
 */
typedef struct qe_device {

	qe_dev_type type;

	char name[CONFIG_DEV_NAME_MAX];

	qe_u16 flag;
	qe_u16 open_flag;

	qe_u16 reference;

	qe_u16 device_id;

	/* device callback */
	qe_dev_rx_indicate_func rx_indicate;
	qe_dev_tx_complete_func tx_complete;

	const qe_dev_ops *ops;

	/* private data */
	void *priv;

	/* register to device list */
	qe_list list;
}qe_dev;

qe_dev *qe_dev_find(qe_const_str name);
qe_ret  qe_dev_register(qe_dev *dev, qe_const_str name, qe_u16 flags);
qe_ret  qe_dev_unregister(qe_dev *dev);
qe_ret  qe_dev_ioctl(qe_dev *dev, qe_int cmd, qe_ptr arg);
qe_ret  qe_dev_close(qe_dev *dev);
qe_ret  qe_dev_open(qe_dev *dev, qe_u16 oflag);
qe_size qe_dev_read(qe_dev *dev, qe_offs pos, qe_ptr buf, qe_size size);
qe_size qe_dev_write(qe_dev *dev, qe_offs pos, qe_const_ptr buf, qe_size size);
qe_ret  qe_dev_set_rx_indicate(qe_dev *dev, qe_dev_rx_indicate_func);
qe_ret  qe_dev_set_tx_complete(qe_dev *dev, qe_dev_tx_complete_func);



#endif /* __QE_DEVICE_H__ */

